#include "stdafx.h"
#include "Box.h"

using namespace unigame;

//@//
/*
	Edges are stored in this way:
	Hey, am I an ascii artist, or what? :) niko.
	   3---------/7 max
	  /|        / |
	 / |       /  |
    1---------5   |
    |  2- - - |- -6
	| /       |  /
	|/        | /
	0---------4/
	min
*/
void Box::edges(Vector3f* v)
{
	v[0].set(m_min.x, m_min.y, m_min.z);
	v[1].set(m_min.x, m_max.y, m_min.z);
	v[2].set(m_min.x, m_min.y, m_max.z);
	v[3].set(m_min.x, m_max.y, m_max.z);
	v[4].set(m_max.x, m_min.y, m_min.z);
	v[5].set(m_max.x, m_max.y, m_min.z);
	v[6].set(m_max.x, m_min.y, m_max.z);
	v[7].set(m_max.x, m_max.y, m_max.z);
}

void Box::recomputeAABB(Matrixf& m, Box& box)
{
	box.m_min.x = m[M_INDEX(0, 3)];
	box.m_min.y = m[M_INDEX(1, 3)];
	box.m_min.z = m[M_INDEX(2, 3)];
	box.m_max = box.m_min;
	if(m[M_INDEX(0, 0)] > 0)
	{
		box.m_min.x += m[M_INDEX(0, 0)] * m_min.x;
		box.m_max.x += m[M_INDEX(0, 0)] * m_max.x;
	}
	else
	{
		box.m_min.x += m[M_INDEX(0, 0)] * m_max.x;
		box.m_max.x += m[M_INDEX(0, 0)] * m_min.x;
	}
	if(m[M_INDEX(0, 1)] > 0)
	{
		box.m_min.x += m[M_INDEX(0, 1)] * m_min.y;
		box.m_max.x += m[M_INDEX(0, 1)] * m_max.y;
	}
	else
	{
		box.m_min.x += m[M_INDEX(0, 1)] * m_max.y;
		box.m_max.x += m[M_INDEX(0, 1)] * m_min.y;
	}
	if(m[M_INDEX(0, 2)] > 0)
	{
		box.m_min.x += m[M_INDEX(0, 2)] * m_min.z;
		box.m_max.x += m[M_INDEX(0, 2)] * m_max.z;
	}
	else
	{
		box.m_min.x += m[M_INDEX(0, 2)] * m_max.z;
		box.m_max.x += m[M_INDEX(0, 2)] * m_min.z;
	}
	
	if(m[M_INDEX(1, 0)] > 0)
	{
		box.m_min.y += m[M_INDEX(1, 0)] * m_min.x;
		box.m_max.y += m[M_INDEX(1, 0)] * m_max.x;
	}
	else
	{
		box.m_min.y += m[M_INDEX(1, 0)] * m_max.x;
		box.m_max.y += m[M_INDEX(1, 0)] * m_min.x;
	}
	if(m[M_INDEX(1, 1)] > 0)
	{
		box.m_min.y += m[M_INDEX(1, 1)] * m_min.y;
		box.m_max.y += m[M_INDEX(1, 1)] * m_max.y;
	}
	else
	{
		box.m_min.y += m[M_INDEX(1, 1)] * m_max.y;
		box.m_max.y += m[M_INDEX(1, 1)] * m_min.y;
	}
	if(m[M_INDEX(1, 2)] > 0)
	{
		box.m_min.y += m[M_INDEX(1, 2)] * m_min.z;
		box.m_max.y += m[M_INDEX(1, 2)] * m_max.z;
	}
	else
	{
		box.m_min.y += m[M_INDEX(1, 2)] * m_max.z;
		box.m_max.y += m[M_INDEX(1, 2)] * m_min.z;
	}

	if(m[M_INDEX(2, 0)] > 0)
	{
		box.m_min.z += m[M_INDEX(2, 0)] * m_min.x;
		box.m_max.z += m[M_INDEX(2, 0)] * m_max.x;
	}
	else
	{
		box.m_min.z += m[M_INDEX(2, 0)] * m_max.x;
		box.m_max.z += m[M_INDEX(2, 0)] * m_min.x;
	}
	if(m[M_INDEX(2, 1)] > 0)
	{
		box.m_min.z += m[M_INDEX(2, 1)] * m_min.y;
		box.m_max.z += m[M_INDEX(2, 1)] * m_max.y;
	}
	else
	{
		box.m_min.z += m[M_INDEX(2, 1)] * m_max.y;
		box.m_max.z += m[M_INDEX(2, 1)] * m_min.y;
	}
	if(m[M_INDEX(2, 2)] > 0)
	{
		box.m_min.z += m[M_INDEX(2, 2)] * m_min.z;
		box.m_max.z += m[M_INDEX(2, 2)] * m_max.z;
	}
	else
	{
		box.m_min.z += m[M_INDEX(2, 2)] * m_max.z;
		box.m_max.z += m[M_INDEX(2, 2)] * m_min.z;
	}
}

void Box::addInternalPoint(float x, float y, float z)
{
	if(x > m_max.x)
	{
		m_max.x = x;
	}
	else if(x < m_min.x)
	{
		m_min.x = x;
	}
	if(y > m_max.y)
	{
		m_max.y = y;
	}
	else if(y < m_min.y)
	{
		m_min.y = y;
	}
	if(z > m_max.z)
	{
		m_max.z = z;
	}
	else if(z < m_min.z)
	{
		m_min.z = z;
	}
}

bool Box::isIntersect1D(float start, float end, float small, float big, float& deltaStart, float& deltaEnd)
{
	if(start == end)
	{
		return start > small && start < big;
	}
	float ds, de;
	if(start < end)
	{
		if(start >= big)
		{
			return false;
		}
		if(end <= small)
		{
			return false;
		}
		float len = end - start;
		if(start >= small)
		{
			ds = 0;
		}
		else
		{
			ds = (small - start) / len;
		}
		if(end <= big)
		{
			de = 1;
		}
		else
		{
			de = (big - start) / len;
		}
		if(ds > deltaStart)
		{
			deltaStart = ds;
		}
		if(de < deltaEnd)
		{
			deltaEnd = de;
		}
		if(deltaStart >= deltaEnd)
		{
			return false;
		}
	}
	else
	{
		if(end >= big)
		{
			return false;
		}
		if(start <= small)
		{
			return false;
		}
		float len = end - start;
		if(start <= big)
		{
			ds = 0;
		}
		else
		{
			ds = (big - start) / len;
		}
		if(end >= small)
		{
			de = 1;
		}
		else
		{
			de = (small - start) / len;
		}
		if(ds > deltaStart)
		{
			deltaStart = ds;
		}
		if(de < deltaEnd)
		{
			deltaEnd = de;
		}
		if(deltaStart >= deltaEnd)
		{
			return false;
		}
	}
	return true;
}

bool Box::isIntersectOrOnEdge1D(float start, float end, float small, float big, float& deltaStart, float& deltaEnd)
{
	if(start == end)
	{
		return start >= small && start <= big;
	}
	float ds, de;
	if(start < end)
	{
		if(start > big)
		{
			return false;
		}
		if(end < small)
		{
			return false;
		}
		float len = end - start;
		if(start >= small)
		{
			ds = 0;
		}
		else
		{
			ds = (small - start) / len;
		}
		if(end <= big)
		{
			de = 1;
		}
		else
		{
			de = (big - start) / len;
		}
		if(ds > deltaStart)
		{
			deltaStart = ds;
		}
		if(de < deltaEnd)
		{
			deltaEnd = de;
		}
		if(deltaStart > deltaEnd)
		{
			return false;
		}
	}
	else
	{
		if(end > big)
		{
			return false;
		}
		if(start < small)
		{
			return false;
		}
		float len = end - start;
		if(start <= big)
		{
			ds = 0;
		}
		else
		{
			ds = (big - start) / len;
		}
		if(end >= small)
		{
			de = 1;
		}
		else
		{
			de = (small - start) / len;
		}
		if(ds > deltaStart)
		{
			deltaStart = ds;
		}
		if(de < deltaEnd)
		{
			deltaEnd = de;
		}
		if(deltaStart > deltaEnd)
		{
			return false;
		}
	}
	return true;
}